package com.example.partyfee.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.partyfee.config.ExcelConfig;
import com.example.partyfee.dto.PartyFeeCalculationDTO;
import com.example.partyfee.dto.PartyFeeQueryDTO;
import com.example.partyfee.entity.PartyFee;
import com.example.partyfee.entity.PartyMember;
import com.example.partyfee.entity.Salary;
import com.example.partyfee.repository.PartyFeeRepository;
import com.example.partyfee.repository.PartyMemberRepository;
import com.example.partyfee.repository.SalaryRepository;
import com.example.partyfee.service.PartyFeeService;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class PartyFeeServiceImpl extends ServiceImpl<PartyFeeRepository, PartyFee> implements PartyFeeService {

    private final PartyMemberRepository partyMemberRepository;
    private final SalaryRepository salaryRepository;
    private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calculatePartyFees(PartyFeeCalculationDTO calculationDTO) {
        // 1. 获取工资数据
        String startMonth = String.format("%d-%02d", calculationDTO.getYear(), 
            calculationDTO.getMonth() != null ? calculationDTO.getMonth() : 1);
        String endMonth = String.format("%d-%02d", calculationDTO.getYear(), 
            calculationDTO.getMonth() != null ? calculationDTO.getMonth() : 12);

        // 2. 按身份证号分组获取工资数据
        List<Salary> allSalaries = salaryRepository.findByMonthBetween(startMonth, endMonth);
        if (allSalaries.isEmpty()) {
            throw new RuntimeException("未找到指定时间范围内的工资数据");
        }

        // 3. 按身份证号分组
        Map<String, List<Salary>> salaryMap = allSalaries.stream()
            .collect(Collectors.groupingBy(Salary::getIdCard));

        // 4. 生成批次号
        String batchNo = UUID.randomUUID().toString();
        LocalDate calculationDate = LocalDate.now();

        // 5. 计算党费
        List<PartyFee> partyFees = new ArrayList<>();
        for (Map.Entry<String, List<Salary>> entry : salaryMap.entrySet()) {
            List<Salary> salaries = entry.getValue();
            Salary firstSalary = salaries.get(0);

            // 验证数据完整性
            if (firstSalary.getPosition() == null || firstSalary.getPosition().trim().isEmpty()) {
                throw new RuntimeException(String.format("身份证号为 %s 的工资记录缺少职务信息", firstSalary.getIdCard()));
            }

            // 计算党费基数
            BigDecimal basicAmount = calculateBasicAmount(firstSalary.getPosition(), salaries);
            
            // 计算费率
            BigDecimal rate = calculateRate(basicAmount);
            
            // 计算应缴党费
            BigDecimal payableAmount = basicAmount.multiply(rate)
                .setScale(2, RoundingMode.HALF_UP);

            // 创建党费记录
            PartyFee partyFee = new PartyFee();
            partyFee.setClassName(firstSalary.getClassName());
            partyFee.setPosition(firstSalary.getPosition());
            partyFee.setName(firstSalary.getName());
            partyFee.setIdCard(firstSalary.getIdCard());
            partyFee.setIdentifier(firstSalary.getIdentifier());
            partyFee.setCalculationDate(calculationDate);
            partyFee.setStartMonth(startMonth);
            partyFee.setEndMonth(endMonth);
            partyFee.setMonthsCount(salaries.size());
            partyFee.setBasicAmount(basicAmount);
            partyFee.setRate(rate);
            partyFee.setPayableAmount(payableAmount);
            partyFee.setPositionLevel(firstSalary.getPosition());
            partyFee.setBatchNo(batchNo);
            partyFee.setCreateTime(LocalDate.now().atStartOfDay());
            
            partyFees.add(partyFee);
        }

        // 6. 批量保存
        if (!partyFees.isEmpty()) {
            this.saveBatch(partyFees);
        }
    }

    @Override
    public IPage<PartyFee> getPartyFees(PartyFeeQueryDTO queryDTO) {
        LambdaQueryWrapper<PartyFee> wrapper = new LambdaQueryWrapper<>();
        
        // 添加查询条件
        if (StringUtils.isNotBlank(queryDTO.getKeyword())) {
            wrapper.like(PartyFee::getName, queryDTO.getKeyword())
                .or()
                .like(PartyFee::getIdCard, queryDTO.getKeyword())
                .or()
                .like(PartyFee::getIdentifier, queryDTO.getKeyword());
        }
        
        if (StringUtils.isNotBlank(queryDTO.getClassName())) {
            wrapper.eq(PartyFee::getClassName, queryDTO.getClassName());
        }
        
        if (StringUtils.isNotBlank(queryDTO.getPosition())) {
            wrapper.eq(PartyFee::getPosition, queryDTO.getPosition());
        }
        
        if (queryDTO.getYear() != null) {
            wrapper.likeRight(PartyFee::getStartMonth, queryDTO.getYear());
        }
        
        wrapper.orderByDesc(PartyFee::getCreateTime);
        
        return this.page(new Page<>(queryDTO.getPage(), queryDTO.getSize()), wrapper);
    }

    @Override
    public void exportPartyFees(PartyFeeQueryDTO queryDTO, HttpServletResponse response)
        throws IOException {
        // 查询数据
        queryDTO.setPage(1);
        queryDTO.setSize(Integer.MAX_VALUE);
        List<PartyFee> partyFees = this.getPartyFees(queryDTO).getRecords();
        
        // 导出Excel
        ExcelConfig.getWriteBuilder(response.getOutputStream(), PartyFee.class)
            .sheet("党费计算结果")
            .doWrite(partyFees);
    }

    private BigDecimal calculateBasicAmount(String position, List<Salary> salaries) {
        int monthsCount = salaries.size();
        BigDecimal totalBasicSalary = BigDecimal.ZERO;
        BigDecimal totalPerformanceSalary = BigDecimal.ZERO;
        BigDecimal totalBonus = BigDecimal.ZERO;
        BigDecimal totalDeductions = BigDecimal.ZERO;

        for (Salary salary : salaries) {
            // 处理基本工资
            totalBasicSalary = totalBasicSalary.add(
                salary.getBasicSalary() != null ? salary.getBasicSalary() : BigDecimal.ZERO);
            
            // 处理绩效工资
            totalPerformanceSalary = totalPerformanceSalary.add(
                salary.getPerformanceSalary() != null ? salary.getPerformanceSalary() : BigDecimal.ZERO);
            
            // 处理个人奖金
            totalBonus = totalBonus.add(
                salary.getIndividualBonus() != null ? salary.getIndividualBonus() : BigDecimal.ZERO);
            
            // 累加扣除项，处理空值
            totalDeductions = totalDeductions
                .add(salary.getEnterprisePension() != null ? salary.getEnterprisePension() : BigDecimal.ZERO)
                .add(salary.getEndowmentInsurance() != null ? salary.getEndowmentInsurance() : BigDecimal.ZERO)
                .add(salary.getUnemploymentInsurance() != null ? salary.getUnemploymentInsurance() : BigDecimal.ZERO)
                .add(salary.getMedicalInsurance() != null ? salary.getMedicalInsurance() : BigDecimal.ZERO)
                .add(salary.getHousingFund() != null ? salary.getHousingFund() : BigDecimal.ZERO)
                .add(salary.getPersonalTax() != null ? salary.getPersonalTax() : BigDecimal.ZERO)
                .add(salary.getDeductionOne() != null ? salary.getDeductionOne() : BigDecimal.ZERO)
                .add(salary.getDeductionTwo() != null ? salary.getDeductionTwo() : BigDecimal.ZERO);
        }

        BigDecimal monthlyBasicSalary = totalBasicSalary.divide(BigDecimal.valueOf(monthsCount), 2, RoundingMode.HALF_UP);
        BigDecimal monthlyPerformanceSalary = totalPerformanceSalary.divide(BigDecimal.valueOf(monthsCount), 2, RoundingMode.HALF_UP);
        BigDecimal monthlyBonus = totalBonus.divide(BigDecimal.valueOf(monthsCount), 2, RoundingMode.HALF_UP);
        BigDecimal monthlyDeductions = totalDeductions.divide(BigDecimal.valueOf(monthsCount), 2, RoundingMode.HALF_UP);

        // 根据职务计算党费基数
        BigDecimal basicAmount;
        if (position == null || position.trim().isEmpty()) {
            // 如果职务为空，只计算基本工资
            basicAmount = monthlyBasicSalary;
        } else {
            switch (position) {
                case "校级干部":
                    basicAmount = monthlyBasicSalary.add(
                        monthlyPerformanceSalary.multiply(new BigDecimal("0.8")));
                    break;
                case "院级干部":
                case "班级干部":
                case "组长":
                    basicAmount = monthlyBasicSalary.add(
                        monthlyPerformanceSalary.multiply(new BigDecimal("0.55")))
                        .add(monthlyBonus.multiply(new BigDecimal("0.3")));
                    break;
                default:
                    basicAmount = monthlyBasicSalary;
            }
        }

        return basicAmount.subtract(monthlyDeductions).setScale(2, RoundingMode.HALF_UP);
    }

    private BigDecimal calculateRate(BigDecimal basicAmount) {
        if (basicAmount.compareTo(new BigDecimal("3000")) <= 0) {
            return new BigDecimal("0.005"); // 0.5%
        } else if (basicAmount.compareTo(new BigDecimal("5000")) <= 0) {
            return new BigDecimal("0.01");  // 1%
        } else if (basicAmount.compareTo(new BigDecimal("10000")) <= 0) {
            return new BigDecimal("0.015"); // 1.5%
        } else {
            return new BigDecimal("0.02");  // 2%
        }
    }
} 